package configx

import (
	"strconv"
	"strings"
	"time"

	"gitee.com/yanwc/gozero-utils/errx"
	"gitee.com/yanwc/gozero-utils/jsonx"
)

type (
	ConfigKey string
	DataType  int
)

const (
	StringType          = DataType(0)
	IntType             = DataType(1)
	BoolType            = DataType(2)
	DateType            = DataType(3)
	NumberType          = DataType(4)
	IntRangeType        = DataType(5)
	NumberRangeType     = DataType(6)
	DateRangeType       = DataType(7)
	DictStringArrayType = DataType(9)
	DictNumberArrayType = DataType(10)
)

type ConfigKeySchema struct {
	Key         ConfigKey
	Type        DataType
	Description string
}

type Option[T any] struct {
	Parse func()
}

type RangeIntValue struct {
	Start int
	End   int
}

type RangeDateValue struct {
	Start time.Time
	End   time.Time
}

type RangeFloat64Value struct {
	Start float64
	End   float64
}

// 解析配置值
func (dt DataType) Value(content string) (interface{}, *errx.Error) {
	if dt == StringType {
		return content, nil
	}

	if dt == IntType || dt == DateType {
		v, err := strconv.Atoi(content)
		if err != nil {
			return nil, errx.NewWithError(errx.STRING_CONVERT_NUMBER, err)
		}

		if dt == DateType {
			return time.Unix(int64(v), 0), nil
		}

		return v, nil
	}

	if dt == BoolType {
		if len(content) == 0 {
			return false, nil
		}

		switch strings.ToLower(content) {
		case "false":
			return false, nil
		case "true":
			return true, nil
		case "1":
			return true, nil
		case "0":
			return false, nil
		default:
			return false, errx.New(errx.SERVER, errx.WithMsgOption("bool类型格式不支持"))
		}
	}

	if dt == IntRangeType || dt == DateRangeType {
		start, end, err := getRangeRawValue(content)
		if err != nil {
			return nil, err
		}

		if s, err := strconv.Atoi(start); err != nil {
			return nil, errx.NewWithError(errx.STRING_CONVERT_NUMBER, err)
		} else if e, err := strconv.Atoi(end); err != nil {
			return nil, errx.NewWithError(errx.STRING_CONVERT_NUMBER, err)
		} else {
			if dt == DateRangeType {
				return RangeDateValue{
					Start: time.Unix(int64(s), 0),
					End:   time.Unix(int64(e), 0),
				}, nil
			} else {
				return RangeIntValue{
					Start: s,
					End:   e,
				}, nil
			}
		}
	}

	if dt == NumberType {
		if s, err := strconv.ParseFloat(content, 64); err != nil {
			return nil, errx.NewWithError(errx.STRING_CONVERT_NUMBER, err)
		} else {
			return s, nil
		}
	}

	if dt == NumberRangeType {
		start, end, err := getRangeRawValue(content)
		if err != nil {
			return nil, err
		}

		if s, err := strconv.ParseFloat(start, 64); err != nil {
			return nil, errx.NewWithError(errx.STRING_CONVERT_NUMBER, err)
		} else if e, err := strconv.ParseFloat(end, 64); err != nil {
			return nil, errx.NewWithError(errx.STRING_CONVERT_NUMBER, err)
		} else {
			return RangeFloat64Value{
				Start: s,
				End:   e,
			}, nil
		}
	}

	if dt == DictStringArrayType {
		if d, e := jsonx.StringToSlice[string](content); e != nil {
			return nil, errx.New(errx.JSON_UNMARSHAL, errx.WithErrorOption(e))
		} else {
			return d, nil
		}
	}

	if dt == DictNumberArrayType {
		if d, e := jsonx.StringToSlice[float64](content); e != nil {
			return nil, errx.New(errx.JSON_UNMARSHAL, errx.WithErrorOption(e))
		} else {
			return d, nil
		}
	}

	return nil, errx.New(errx.BIZ, errx.WithMsgOption("类型不支持"))
}

func getRangeRawValue(content string) (start string, end string, err *errx.Error) {
	if len(content) == 0 {
		err = errx.New(errx.CONFIG_RANGE_FORMAT)
		return
	}

	data := strings.Split(content, ",")
	if len(data) != 2 {
		err = errx.New(errx.CONFIG_RANGE_FORMAT)
		return
	}

	if strings.Index(data[0], "[") != 0 {
		err = errx.New(errx.CONFIG_RANGE_FORMAT)
		return
	}

	if strings.LastIndex(data[1], "]") != len(data[1])-1 {
		err = errx.New(errx.CONFIG_RANGE_FORMAT)
		return
	}

	start = strings.Trim(strings.Trim(data[0], "("), "[")
	end = strings.Trim(strings.Trim(data[1], ")"), "]")

	return
}
